/**
 * Simple Chord node implementation in Java
 **/

package core1;

import java.util.Map.Entry;
import java.util.Random;

import processing.core.PApplet;


public class StandAloneChordNode extends ChordNode implements Nodeable {
	private int tick = 0;

	public StandAloneChordNode(PApplet parent) {
		super(parent);
		init();
	}
	public StandAloneChordNode(PApplet parent, long key) {
		super(parent, key);
		init();
	}
	
	private void init() {
		nextKey = getKey();
		previousKey = getKey();
		
		user = this;
		next = this;
		previous = this;
		
		//Create empty finger table
		
		for (Long key:fingerTable.keySet()) {
			fingerTable.put(key, this);
		}
	}
	
	public Nodeable ClosestFinger(long key){
		for (Entry<Long,Nodeable> finger :fingerTable.entrySet()) {
			Nodeable node = finger.getValue();
			long fingerKey= node.getKey();
			if ( Globals.interval_check_inc_inc(fingerKey, key, getKey()))
					return node;
		}
		return next;
	};
	
	public void update() {
		super.update();
		if ( tick==0 && globals.networkMode== globals.CHORD_MODE)
			updateRandomFinger();
		
		tick = ((tick+1) % globals.fingerUpdateFrequency);
	}
	
	// find() 
	// recursive lookup of responsible node

	public Nodeable find(long key)
	{
		long myKey = getKey(); 
		if (this == next) 
			return this;
		
		StandAloneChordNode next = (StandAloneChordNode) this.next;
		
		if (key <= nextKey & key > myKey )
			return next;
		//special case, end of the chord RING
		if (myKey > nextKey & (key <= nextKey | key > myKey ))
			return next;

		return next.find(key); // not pure chord sorry :(

	}

	public void updateFingerTable()
	{
		for (Long key:fingerTable.keySet())
		{
			fingerTable.put(key, find(key));
		}

	}
	
	public void updateRandomFinger()
	{
		int index = new Random().nextInt(fingerTable.size());
		Long selection = (Long) fingerTable.keySet().toArray()[index];
		
		fingerTable.put(selection, find(selection));
	}

	public void addMeToYourChord(StandAloneChordNode memberNode) {
		long myKey = getKey();
		setNext( memberNode.find(myKey));
		setPrevious (next.getPrevious());

		next.setPrevious(this);
		previous.setNext(this);

		updateFingerTable();
		next.refreshElements();
	}

	public void addElement(ChordElement e){

		Nodeable target = find(e.getKey());

		if (target == this)
			elements.add(e);
		else target.addElement(e);
	
	}

	public void refreshElements()
	{
		for(int a = 0; a <  elements.size();a++)
		{ 
			ChordElement e= elements.get(a);
			Nodeable target = find(e.getKey());
			if (target != this){
				target.addElement(e);
				target.setPhysicalView();
				elements.remove(e);
				a--;
			}
		}
	}
	public void drawTargetNodeHint(float scale) {
		float x= getXpos();
		float y= getYpos();
		float size = globals.nodeSize/2;
		
		parent.stroke(globals.targetNodeHintColor);
		parent.strokeWeight(2/scale);
		
		parent.ellipse(x, y, size/scale, size/scale);
	}
}
